#!/usr/bin/python
# -*- coding: utf-8 -*-

__author__ = 'byrne_000'
import argparse
import boto
import boto.ec2
import boto.rds
from config import config
import utils
from utils import N
from utils import tag
import time
import deploy_net


class DBDeployment:
    def __init__(self):
        self.sg = None  # SecurityGroup
        self.subnet_group = None  # Subnet group
        self.sg_rule_exist = False
        self.subnets = None
        self.instance = None


def query_db():
    print('Checking deployment status...')
    net = deploy_net.query_net()

    db = DBDeployment()
    db.subnets = [sb[0] for sb in net.nets if sb[0] and not sb[1]]
    if not db.subnets:
        raise RuntimeError('Warning: no private subnets exist!')

    ec2_conn = boto.ec2.connect_to_region(config.REGION)
    if ec2_conn is None:
        raise RuntimeError(N('Fail to connect to region({0}) by ec2', config.REGION))
    rds_conn = boto.rds.connect_to_region(config.REGION)
    if rds_conn is None:
        raise RuntimeError(N('Fail to connect to region({0}) by RDS', config.REGION))

    sgs = ec2_conn.get_all_security_groups(filters={"group_name": config.db.SecurityGroup['NAME']})
    if len(sgs) == 1:
        db.sg = sgs[0]

        for rule in db.sg.rules:
            if (rule.ip_protocol, int(rule.from_port), int(rule.to_port), [src.group_id for src in rule.grants]) == \
                    ('tcp', config.db.DB_PORT, config.db.DB_PORT, [db.sg.id]):
                db.sg_rule_exist = True
    try:
        groups = rds_conn.get_all_db_subnet_groups(name=config.db.SUBNET_GROUP['NAME'])
    except boto.exception.BotoServerError as res:
        if res.error_code == 'DBSubnetGroupNotFoundFault':
            pass
        else:
            raise res
    else:
        db.subnet_group = groups[0]

    try:
        instances = rds_conn.get_all_dbinstances(config.db.INSTANCE_NAME)
    except boto.exception.BotoServerError as res:
        if res.error_code == 'DBInstanceNotFound':
            pass
        else:
            raise res
    else:
        db.instance = instances[0]

    print('Checking deployment status...Done')

    if db.sg:
        utils.print_sg(db.sg)
    if db.subnets:
        print(db.subnets)
    if db.subnet_group:
        print('Subnets Group:\n\tName:%s\n\tDescription:%s\n\tSubnets:%s' % (
            db.subnet_group.name, db.subnet_group.description, db.subnet_group.subnet_ids))
    if db.instance:
        print('Instance:\n\tName:%s\n\tCreation:%s\n\tEndpoint:%s'
              '\n\tEngine:%s%s\n\tInstance type:%s'
              '\n\tSize:%d\n\tIOPS:%r'
              '\n\tDBName:%s\n\tUsername:%s\n\tAcross Multi Zones:%r'
              '\n\tParameter group:%s\n\tSubnet group:%s\n\tVPC security group:%s' % (
                  db.instance.id, db.instance.create_time, db.instance.endpoint,
                  db.instance.engine, db.instance.engine_version, db.instance.instance_class,
                  db.instance.allocated_storage, db.instance.iops,
                  db.instance.DBName, db.instance.master_username, db.instance.multi_az,
                  db.instance.parameter_group, db.instance.subnet_group, db.instance.vpc_security_groups))
    return db


def setup_db(db):
    ec2_conn = boto.ec2.connect_to_region(config.REGION)
    if ec2_conn is None:
        raise RuntimeError(N('Fail to connect to region({0}) by ec2', config.REGION))

    if not db.sg:
        sg_db = ec2_conn.create_security_group(config.db.SecurityGroup['NAME'],
                                               config.db.SecurityGroup['DESC'],
                                               vpc_id=config.VPC_ID)
        tag(sg_db, config.db.SecurityGroup['NAME'])
        db.sg = sg_db

    if not db.sg_rule_exist:
        db.sg.authorize('tcp', config.db.DB_PORT, config.db.DB_PORT, src_group=db.sg)
        db.sg_rule_exist = True

    rds_conn = boto.rds.connect_to_region(config.REGION)
    if rds_conn is None:
        raise RuntimeError(N('Fail to connect to region({0}) by RDS', config.REGION))

    if not db.subnet_group:
        db.subnet_group = rds_conn.create_db_subnet_group(name=config.db.SUBNET_GROUP['NAME'],
                                                          desc=config.db.SUBNET_GROUP['DESC'],
                                                          subnet_ids=[i.id for i in db.subnets])

    if not db.instance:
        db.instance = rds_conn.create_dbinstance(config.db.INSTANCE_NAME, config.db.INIT_SIZE, config.db.INSTANCE_TYPE,
                                                 config.db.USER_NAME, config.db.USER_PASSWORD, engine='MySQL',
                                                 db_name=config.db.DB_NAME,
                                                 availability_zone=config.AZ1, multi_az=False,
                                                 db_subnet_group_name=config.db.SUBNET_GROUP['NAME'],
                                                 # option_group_name=DB_OPTION_GROUP,
                                                 vpc_security_groups=[db.sg.id])


def remove_db(db):
    ec2_conn = boto.ec2.connect_to_region(config.REGION)
    rds_conn = boto.rds.connect_to_region(config.REGION)

    if db.instance:
        rds_conn.delete_dbinstance(db.instance.id, skip_final_snapshot=True)
        done = False
        while not done:
            time.sleep(5)
            try:
                instances = rds_conn.get_all_dbinstances(config.db.INSTANCE_NAME)
            except boto.exception.BotoServerError as res:
                if res.error_code == 'DBInstanceNotFound':
                    done = True
                else:
                    raise res
            print('deleting database instance...')
        print('Delete done.')

    if db.sg:
        ec2_conn.delete_security_group(group_id=db.sg.id)

    if db.subnet_group:
        rds_conn.delete_db_subnet_group(db.subnet_group.name)

    pass


if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument('mode', metavar='command', choices=['setup', 'query', 'remove'],
                        default='setup', type=str, help='setup mode or remove mode')
    args = parser.parse_args()
    if args.mode == 'remove':
        db = query_db()
        remove_db(db)
        print('Updated information==============')
        query_db()
    elif args.mode == 'query':
        db = query_db()
    else:
        db = query_db()
        setup_db(db)
        print('Updated information==============')
        query_db()
